import type { Ref, WatchSource } from 'vue'
import type { EmitVoid, UnWrapRefObject } from './utils'
import type { CacheData, CacheKey } from '../plugins/useCachePlugin'

export interface Mutate<Data> {
  (newData: Data): void
  (arg: (oldData: Data) => Data): void
}

export type StateBindParams<Data = any, P extends unknown[] = any[]> = State<Data, P> & { status: Ref<StatusType> }

export type StatusType = 'pending' | 'settled'

export type Service<Data, P extends unknown[] = any[]> = (...args: P) => Promise<Data>

export interface State<Data, P> {
  loading: Ref<boolean>
  data: Ref<Data | undefined>
  error: Ref<Error | undefined>
  params: Ref<P>
}

export interface FunctionContext<Data, P extends unknown[]> {
  runAsync: (...arg: P) => Promise<Data>
  run: (...arg: P) => void
  cancel: () => void
  refresh: () => void
  refreshAsync: () => Promise<Data>
  mutate: Mutate<Data>
}

export interface Fetch<Data, P extends unknown[]> extends State<Data, P> {
  status: Ref<StatusType>
  context: FunctionContext<Data, P>
  plugins: Ref<Partial<PluginType<Data, P>>[]>
}

export interface FetchResult<Data = any, P extends unknown[] = any[]> extends State<Data, P>, FunctionContext<Data, P> {}

export interface BaseOptions {
  /** 是否手动发起请求 */
  manual?: boolean
  /** 准备状态，处理依赖请求 */
  ready?: Ref<boolean> | (() => boolean)
  /** 轮询的间隔时间（毫秒） */
  pollingInterval?: number | Ref<number>
  /** 屏幕不可见时轮询 */
  pollingWhenHidden?: boolean
  /** 窗口聚焦时重新请求 */
  refreshOnWindowFocus?: boolean | Ref<boolean>
  /** 重新聚焦间隔时间（毫秒） */
  refocusInterval?: number | Ref<number>
  /** 缓存的过期时间（毫秒），默认为 600000 毫秒，即 10 分钟 */
  cacheTime?: number
  /** 缓存数据保鲜时间（毫秒），0：缓存不保鲜，每次都会重新发起请求；-1：缓存永不过期 */
  staleTime?: number
  /** 依赖刷新 */
  refreshDeps?: WatchSource | WatchSource[]
  /** 自定义依赖刷新的行为 */
  refreshDepsAction?: () => void
  /** 自定义设置缓存 */
  getCache?: (cacheKey: CacheKey) => CacheData
  /** 自定义读取缓存 */
  setCache?: (cacheKey: CacheKey, cacheData: CacheData) => void
}

export interface Options<Data = any, P extends unknown[] = any[]> extends BaseOptions {
  /** 当 manual 为false时，自动执行的默认参数 */
  defaultParams?: P
  /** 缓存 key */
  cacheKey?: CacheKey | ((params?: P) => CacheKey)
  /** 请求成功回调；注：在缓存策略中是不会执行 onSuccess 回调 */
  onSuccess?: (data: Data, params: P) => void
  /** 请求失败回调 */
  onError?: (error: Error, params: P) => void
  /** 请求之前回调 */
  onBefore?: (params: P) => void
  /** 请求之后回调 */
  onAfter?: (params: P) => void
}

export type FP<Data = any, P extends unknown[] = any> = FunctionPlugin<Data, P>

export interface FunctionPlugin<Data = any, P extends unknown[] = any> {
  (fetchInstance: Fetch<Data, P>, config: Options<Data, P>): Partial<PluginType<Data, P>>
}

export interface PluginType<Data, P extends unknown[]> {
  onBefore: (params: P) => ({ isBreak?: boolean; isReturn?: boolean } & Partial<UnWrapRefObject<State<Data, P>>>) | void
  onFetch: (service: () => Promise<Data>) => () => Promise<Data>
  onSuccess(data: Data, params: P): void
  onError(error: Error, params: P): void
  onAfter(params: P, data: Data, error: Error): void
  onCancel(): void
  onMutate(data: Data): void
}

export type EmitResults<Data, P extends unknown[]> = EmitVoid<ReturnType<PluginType<Data, P>['onBefore']>> & {
  servicePromise: Promise<Data>
}
